<?php

namespace Service\SearchService;

use Hyperf\Elasticsearch\ClientBuilderFactory;
use Service\BaseService;
use Service\HttpServer\Http;
use Service\ExtraService\IdService;
use App\Model\SearchLogModel\ElasticsearchLog;

/**
 * 搜索服务基础连接类
 * @author chenshubo
 */
class BaseElasticSearchClientService extends BaseService
{
    public $client;
    public $index;
    public $url;
    public $mapping_property = [];
    public function __construct()
    {
        $endpoint = env('ELASTIC_SEARCH_ENDPOINT');
        $this->url = "http://".$endpoint;
        $builder = container()->get(ClientBuilderFactory::class)->create();
        $this->client = $builder->setHosts([
            $endpoint,
        ])->build();
    }
    
    /**
     * 创建文档索引模板
     */
    public function createMapping( $index = null )
    {
        $param = [
            'index' => $index ? $index : $this->index,
            'body'  => [
                'settings' => [
                    'number_of_shards'      => 3,
                    'number_of_replicas'    => 1,
                    "index.refresh_interval" => "15s",
                    'analysis'  => [
                        'pinyin_filter' => [
                            "type"  => "pinyin",
                            "keep_first_letter" => true
                        ],
                        'analyzer'  => [
                            'ik_pinyin_analyzer'   => [
                                'type'      => 'pinyin',
                                'tokenizer' => 'ik_smart',
                                'filter'    => 'pinyin_filter'
                            ]
                        ]
                    ],
                ],
                'mappings'  => [
                    'properties' => $this->mapping_property,
                ]
            ]
        ];
        return $this->client->indices()->create($param);
    }
    
    /**
     * 关闭索引使用
     * @param unknown $index
     */
    public function closeIndex( $index = null )
    {
        $index = $index ? $index : $this->index;
        $param = [
            'index' => $index,
        ];
        return $this->client->indices()->close($param);
    }    

    /**
     * 开启索引使用
     * @param unknown $index
     */
    public function openIndex( $index = null )
    {
        $index = $index ? $index : $this->index;
        $param = [
            'index' => $index,
        ];
        return $this->client->indices()->open($param);
    }
    
    /**
     * 开启索引使用
     * @param unknown $index
     */
    public function putIndexSetting( $index = null )
    {
        $index = $index ? $index : $this->index;
        $param = [
            'index' => $index,
            'body'  => [
                'index' => [
                    'analysis'  => [
                        'analyzer'  => [
                            'ik_pinyin_analyzer'    => [
                                'type'      => 'custom',
                                'tokenizer' => 'ik_max_word',
                                'filter'    => 'pinyin_filter'
                            ],
                        ],
                        'filter' => [
                            'pinyin_filter' => [
                                'type'  => 'pinyin',
                                'keep_first_letter'=> false
                            ]
                        ]
                    ]
                ]
            ]
        ];
        return $this->client->indices()->putSettings($param);
    }
    
    /**
     * 分词分析
     */
    public function analyze( string $keyword )
    {
        $keyword = str_replace(" ", "", $keyword);
        $param = [
            'body'  => [
                'analyzer'  =>  'ik_smart',
                'text'      =>  $keyword
            ]
        ];
        return $this->client->indices()->analyze($param);
    }
    
    /**
     * 添加文档
     */
    public function addDoc($param)
    {
        return $this->client->create($param);
    }
    
    /**
     * write with block
     */
    public function bulk($param)
    {
        $param = [
            'body'  => $param,
        ];
        return $this->addRequestLog('bulk', $param);
    }
    
    /**
     * delete all
     */
    public function deleteByQuery( $param = [] )
    {
        return $this->addRequestLog('deleteByQuery', $param);
    }

    /**
     * update all
     */
    public function updateByQuery( $param = [] )
    {
        return $this->addRequestLog('updateByQuery', $param);
    }
    
    /**
     * Deletes an index.
     */
    public function delMapping( $index = null)
    {
        $index = $index ? $index : $this->index;
        $param = [
            'index' => $index,
        ];
        return $this->client->indices()->delete($param);
    }
    
    /**
     * get Index Mapping
     */
    public function getMapping( $index = null )
    {
        $index = $index ? $index : $this->index;
        $param = [
            'index' => $index,
        ];
        return $this->client->indices()->getMapping($param);
    }
    
    /**
     * 获取索引
     */
    public function getIndices( $index = null )
    {
        $index = $index ? $index : $this->index;
        $param = [
            'index' => $index,
        ];
        return $this->client->cat()->indices($param); 
    }
    
    /**
     * 获取全部的索引
     */
    public function getAllIndices()
    {
        return $this->client->cat()->indices();
    }
    
    /**
     * 判断索引是否存在
     */
    public function existsIndices( $index = null)
    {
        $index = $index ? $index : $this->index;
        $param = [
            'index' => $index,
        ];
        return $this->client->indices()->exists($param);
    }
    
    /**
     * 分组数据
     * @param array $param
     */
    public function getAggsList( $param = [] )
    {
        return $this->addRequestLog('search', $param);
    }
    
    /**
     * 请求并且写入日志
     * @param string $method
     * @param array $param
     */
    private function addRequestLog(string $method,array $param)
    {
        $start = microtime(true);
        if( $method == 'updateByQuery' ) {
            $url = $this->url."/".$this->index.'/_update_by_query?wait_for_completion=false';
            $response = Http::postJsonCurl($url,$param['body']);
            
            $response = @json_decode($response,true);
        } else {
            $response = $this->client->{$method}($param);
        }
        ElasticsearchLog::instance()->insert([
            'id'                => IdService::instance()->getLogID(),
            'index'             => $this->index,
            'index_method'      => $method,
            'index_request'     => json_encode($param,JSON_UNESCAPED_UNICODE),
            'index_response'    => is_array($response) ? json_encode($response,JSON_UNESCAPED_UNICODE) : $response,
            'request_time'      => time(),
            'request_used_time' => bcsub((string)microtime(true),(string)$start,3)
        ]);
        return $response;
    }
}